package com.my.lambda;

import cn.hutool.core.collection.ListUtil;
import com.my.lambda.domian.Product;
import com.my.lambda.domian.TestEntity;
import com.my.lambda.domian.User;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.data.domain.Sort;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 数据源：（集合、数组--创建流）- 在传输中做流水线式的"中间操作" - 产生新的流(终止操作)
 */
@Slf4j
public class LambdaStreamTest {

    /*简单流操作*/
    @Test
    public void test1() {
        //1.Collection
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        //2.arrays
        String[] strings = new String[10];
        Stream<String> stream1 = Arrays.stream(strings);
        //3.Stream 的静态方法
        Stream<String> stringStream = Stream.of("1", "2");
        //4.无限流
        //迭代
        Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 2);
//        iterate.forEach(System.out::println);//此处无限操作
        iterate.limit(10).forEach(System.out::println);
        //生成
        Stream<Double> generate = Stream.generate(Math::random);
        generate.limit(10).forEach(System.out::println);

    }

    /**
     * 中间操作  惰性求值---中间操作会在最后结束时执行 如打印
     * map：通过一个 Function 把一个元素类型为 T 的流转换成元素类型为 R 的流。
     * flatMap：通过一个 Function 把一个元素类型为 T 的流中的每个元素转换成一个元素类型为 R 的流，再把这些转换之后的流合并。
     * <p>
     * filter：过滤流中的元素，只保留满足由 Predicate 所指定的条件的元素。
     * distinct：使用 equals 方法来删除流中的重复元素。
     * limit：截断流使其最多只包含指定数量的元素。
     * skip：返回一个新的流，并跳过原始流中的前 N 个元素。
     * sorted：对流进行排序。
     * peek：返回的流与原始流相同。当原始流中的元素被消费时，会首先调用 peek 方法中指定的 Consumer 实现对元素进行处理。
     * dropWhile：从原始流起始位置开始删除满足指定 Predicate 的元素，直到遇到第一个不满足 Predicate 的元素。
     * takeWhile：从原始流起始位置开始保留满足指定 Predicate 的元素，直到遇到第一个不满足 Predicate 的元素。
     */
    /*简单流使用示例*/
    @Test
    public void test2() {
        List<TestEntity> arr = TestEntity.arry;
        System.out.println("=================filter=======================");
        Stream<TestEntity> stream = arr.stream()
                .filter(e -> e.getAge() > 20);//Predicate

        stream.forEach(System.out::println);
        System.out.println("=================limit=======================");
        arr.stream().limit(2)
                .filter((e) -> {
                    System.out.println("123");
                    return e.getSar() > 30;
                })
                .forEach(System.out::println);
        System.out.println("=====================map===================");
        arr.stream().map(x -> x.getAge() + 1000).forEach(System.out::println);
        TestEntity.strings.stream().map((e) -> e.toUpperCase()).forEach(System.out::println);
        System.out.println("========================================");
    }

    /**
     * 截止操作
     */
    @Test
    public void test3() {
        List<TestEntity> arr = TestEntity.arry;
        System.out.println(arr);
        log.info("aaa",arr);
        log.info(arr.toString());
        //去重
        List<TestEntity> distinctList = arr
                //collectingAndThen收集然后在
                .stream().collect(
                        Collectors.collectingAndThen(
                                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))),
                                ArrayList::new
                        )
                );
        System.out.println(distinctList);
        //排序List<entity>
        List<TestEntity> collect = distinctList.stream().sorted(Comparator.comparing(TestEntity::getSar).reversed()).collect(Collectors.toList());
        System.out.println(collect);
        List<TestEntity> collect2 = distinctList.stream().sorted(Comparator.comparing(TestEntity::getSar)).collect(Collectors.toList());
        System.out.println(collect2);
        //List<entity> --> map
        Map<String, Integer> collect1 = collect2.stream().collect(Collectors.toMap(TestEntity::getName, TestEntity::getAge));
        System.out.println(collect1);
        // List<Map --> Map<xxx, xxx>
        Map<String, Integer> map = new HashMap<>();
        map.put("name", 1212);
        map.put("age", 1212);
        Map<String, Integer> map2 = new HashMap<>();
        map2.put("name", 1211112);
        map2.put("age", 1211112);

        //分页查询时的sort
        List sortList = new ArrayList();
        map.forEach((k,v)->{
            Sort.Order asc = Sort.Order.asc(k);
            sortList.add(asc);
            Sort.by(asc);

            log.info(k+":"+v);
        });
        Sort.by(sortList);

        List<Map<String, Integer>> allNameAndId = new ArrayList<Map<String, Integer>>(Arrays.asList(map, map2));
        Set<Integer> xxx = allNameAndId.stream().collect(
                Collectors.mapping(x -> x.get("xxx"), Collectors.toSet())
        );
        Set<Integer> xxx1 = allNameAndId.stream().map(x -> x.get("xxx")).collect(Collectors.toSet());
        //(v1,v2)->v1 key重复
        Map<String, Integer> allNameAndIds = allNameAndId.stream().collect(
                Collectors.toMap(x -> x.get("name").toString(),
                        x -> Integer.valueOf(x.get("age").toString()), (v1, v2) -> v1));
        System.out.println(allNameAndIds);
//        Map<String, Set<String>> prodMap = prodList.stream().collect(
//                Collectors.groupingBy(Product::getCategory, Collectors.mapping(Product::getName, Collectors.toSet()))
//        );
//        Map<String, Set<String>> prodMap = persons.stream().collect(
//                Collectors.groupingBy(x->x.get("point_id"), Collectors.toSet())
//        );


        List<User> users = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            users.add(new User((long) i, "AnswerAIL" + i, i));
        }
//        Set<Long> ids = users.stream().map(User::getId).collect(Collectors.toSet());
        // 获取 users 集合中的 id 集合
        List<Long> ids = users.stream().map(User::getId).collect(Collectors.toList());
        System.out.println("ids: " + ids);
        System.out.println();

        // 获取 users 集合中的 id 集合并转为字符串, 通过 , 拼接
        String idsTxt = users.stream().map(User::getId).map(String::valueOf).collect(Collectors.joining(","));
        System.out.println("idsTxt: " + idsTxt);
        System.out.println();

        List<String> names = users.stream()
                .map(User::getName)
                .filter(x -> StringUtils.isNotBlank(x))
                .collect(Collectors.toList());
        System.out.println("names: " + names);
        System.out.println();

        String txt = names.stream().collect(Collectors.joining(","));
        System.out.println("txt: " + txt);
        System.out.println();

        txt = names.stream().collect(Collectors.joining(",", "(", ")"));
        System.out.println("txt: " + txt);
        users.forEach(a -> a.setId(1L));
        users = users.stream().map(detailVo -> {
            User detail = new User();
//            BeanUtils.copyProperties(detailVo, detail);
            detail.setAge(1);
            return detail;
        }).collect(Collectors.toList());

        List<Map> collect3 = users.stream().map(a -> {
            Map v = new HashMap();
            v.put(a.getId(), a.getName());
            return v;
        }).collect(Collectors.toList());
        //List<Map> -- > list<String>
        List<String> collect4 = collect3.stream().map(a -> {
            AtomicReference<String> c = new AtomicReference<>(new String());
            a.forEach((k, v) -> {
                c.set(String.valueOf(v));
            });
            return c.toString();
        }).collect(Collectors.toList());
        log.info(collect4.toString());

        /*分组*/
        Product prod1 = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食");
        Product prod2 = new Product(2L, 2, new BigDecimal("20"), "饼干", "零食");
        Product prod3 = new Product(3L, 3, new BigDecimal("30"), "月饼", "零食");
        Product prod4 = new Product(4L, 3, new BigDecimal("10"), "青岛啤酒", "啤酒");
        Product prod5 = new Product(5L, 10, new BigDecimal("15"), "百威啤酒", "啤酒");
        List<Product> prodList = ListUtil.list(false, prod1, prod2, prod3, prod4, prod5);

        prodList.stream().collect(Collectors.counting());
        int sum_price = prodList.stream().mapToInt(Product::getNum).sum();

        Map<String, Set<String>> prodMap = prodList.stream().collect(
                Collectors.groupingBy(Product::getCategory, Collectors.mapping(Product::getName, Collectors.toSet()))
        );
        //{"啤酒":["青岛啤酒","百威啤酒"],"零食":["面包","饼干","月饼"]}
        Map<String, Product> prodMap1 = prodList.stream().collect(
                Collectors.groupingBy(
                        Product::getCategory,
                        Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Product::getNum)), Optional::get)
                )
        );
        //{"啤酒":{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15},"零食":{"category":"零食","id":3,"name":"月饼","num":3,"price":30}}
        Map<String, Integer> prodMap2 = prodList.stream().collect(
                Collectors.groupingBy(Product::getCategory, Collectors.summingInt(Product::getNum))
        );
        //{"啤酒":13,"零食":6}
        Map<String, Long> prodMap3 = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.counting()));
        //{"啤酒":2,"零食":3}
        Map<String, Map<String, List<Product>>> prodMap4 = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.groupingBy(item -> {
            if (item.getNum() < 3) {
                return "3";
            } else {
                return "other";
            }
        })));
        //{"啤酒":{"other":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}]},"零食":{"other":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30}],"3":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}}
        Map<String, List<Product>> prodMap5 = prodList.stream().collect(Collectors.groupingBy(item -> {
            if (item.getNum() < 3) {
                return "3";
            } else {
                return "other";
            }
        }));
        //{"other":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30},{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"3":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}
        Map<String, List<Product>> prodMap6 = prodList.stream().collect(Collectors.groupingBy(item -> item.getCategory() + "_" + item.getName()));
        //{"零食_月饼":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30}],"零食_面包":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5}],"啤酒_百威啤酒":[{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"啤酒_青岛啤酒":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10}],"零食_饼干":[{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}
        Map<String, List<Product>> prodMap7 = prodList.stream().collect(Collectors.groupingBy(Product::getCategory));
        //{"啤酒":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"零食":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20},{"category":"零食","id":3,"name":"月饼","num":3,"price":30}]}

        //.flatMap List<List<String>> -> List<String>
//        StudentChargeUpdateVo studentChargeUpdateVo = new StudentChargeUpdateVo();
//        List<List<String>> collect11 = studentChargeUpdateVo.getStudentShifts()
//                .stream().map(
//                        x -> x.getStudentShiftsCharges().stream().map(y -> y.getId().toString())
//                                .collect(Collectors.toList())
//                )
//                .collect(Collectors.toList());
//        List<String> collect22 = collect.stream().flatMap(x -> x.stream()).collect(Collectors.toList());
//        System.out.println(1);
    }

    @Data
    public class StudentChargeUpdateVo {

        private List<StudentShifts> studentShifts;

        @Data
        public class StudentShifts {
            /**
             * 缴费信息
             */
            private List<StudentShiftsCharge> studentShiftsCharges;

            @Data
            public class StudentShiftsCharge {
                @NotNull
                private Long id;
            }
        }

    }

    /**
     * 五种求和方式
     *
     * @Author: Mr.li
     * @Date: 2020/9/8
     */
//    @Test
//    public void demo3(){
//        List<Person> personlist = new ArrayList<>();
//        Person person = new Person();
//        for(int i=0;i<10;i++){
//            person.setId(i);
//            person.setName("你好=="+i);
//            personlist.add(person);
//        }
//        Long firstSum = personlist.stream()
//                .collect(Collectors.summarizingLong(Person::getId)).getSum();
//        Long secondSum = personlist.stream()
//                .collect(Collectors.summingLong(Person::getId));
//        int thirdSum = personlist.stream()
//                .mapToInt(Person::getId).sum();
//        Integer forthSum = personlist.stream()
//                .collect(Collectors.reducing(0,Person::getId,(i,j)->i+j));
//
//        IntSummaryStatistics stats = personlist.stream().mapToInt(Person::getId).summaryStatistics();
//        Long fiveSum = stats.getSum();
//        System.out.println(firstSum + ":" + secondSum + ":" + thirdSum + ":" + forthSum + ":" + fiveSum);
//
//    }
    @Test
    public void demo4() {
//        QueryWrapper<User> queryWrapper = QueryGenerator.initQueryWrapper(User, req.getParameterMap());
//        queryWrapper.and(wrapper -> wrapper.in("community_code",userCommunityCodes));
//
//        if (org.apache.commons.lang.StringUtils.isNotBlank(communityCode)) {
//            String[] communityCodes = communityCode.split(",");
//            queryWrapper.and(Wrapper -> {
//                Arrays.stream(communityCodes).forEach(otp -> {
//                    Wrapper.or().likeRight("community_code", otp);
//                });
//            });
//        }

        // 日期格式化
//        DateTime parseStartTime  = DateUtil.parse(startTime);
//        DateTime parseEndTime  = DateUtil.parse(endTime);
//        Date beginOfDay = DateUtil.beginOfDay(parseStartTime);
//        Date endOfDay = DateUtil.endOfDay(parseEndTime);
//        lambdaQueryWrapper.and(wrapper -> wrapper
//                .between(SysArticle::getUpDate, beginOfDay,endOfDay)
//                .or(wrapper2 -> wrapper2
//                        .between(SysArticle::getDownDate, beginOfDay,endOfDay)
//                )
//        );

//        lambdaQueryWrapper.apply("AAE013"+" like {0}", personTheme+"%");

//        LambdaQueryWrapper queryWrapper = Wrappers.<StudentQuestionAnswer>lambdaQuery()
//                .eq(StudentQuestionAnswer::getQuestionInfoId, questionInfoId)
//                .last(" limit 1");
    }

}
